package xyz.yuzegod.megawalls.tellraw;

import org.bukkit.Bukkit;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;

public abstract class ItemSerialize
{
    static ItemSerialize itemSerialize;
    
    public static String $(final ItemStack item) {
        return ItemSerialize.itemSerialize.parse(item);
    }
    
    public abstract String parse(final ItemStack p0);
    
    public abstract String getName();
    
    static {
        try {
            ItemSerialize.itemSerialize = new Automatic();
        }
        catch (IllegalStateException e) {
            ItemSerialize.itemSerialize = new Manual();
        }
    }
    
    static class Automatic extends ItemSerialize
    {
        private static boolean inited;
        private static Method asNMSCopyMethod;
        private static Method nmsSaveNBTMethod;
        private static Class<?> nmsNBTTagCompound;
        private static String ver;
        
        public Automatic() {
            if (!Automatic.inited) {
                throw new IllegalStateException("无法初始化自动处理类!");
            }
        }
        
        private static Class getOBCClass(final String cname) throws ClassNotFoundException {
            return Class.forName("org.bukkit.craftbukkit." + Automatic.ver + "." + cname);
        }
        
        @Override
        public String getName() {
            return "Automatic";
        }
        
        @Override
        public String parse(final ItemStack item) {
            try {
                return Automatic.nmsSaveNBTMethod.invoke(Automatic.asNMSCopyMethod.invoke(null, item), Automatic.nmsNBTTagCompound.newInstance()).toString();
            }
            catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | InstantiationException ex2) {
                Automatic.itemSerialize = new Manual();
                return Automatic.itemSerialize.parse(item);
            }
        }
        
        static {
            Automatic.inited = false;
            Automatic.ver = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
            try {
                final Class<?> cis = (Class<?>)getOBCClass("inventory.CraftItemStack");
                Automatic.asNMSCopyMethod = cis.getMethod("asNMSCopy", ItemStack.class);
                final Class<?> nmsItemStack = Automatic.asNMSCopyMethod.getReturnType();
                for (final Method method : nmsItemStack.getMethods()) {
                    final Class<?> rt = method.getReturnType();
                    if (method.getParameterTypes().length == 0 && "NBTTagCompound".equals(rt.getSimpleName())) {
                        Automatic.nmsNBTTagCompound = rt;
                    }
                }
                for (final Method method : nmsItemStack.getMethods()) {
                    final Class<?>[] paras = method.getParameterTypes();
                    final Class<?> rt2 = method.getReturnType();
                    if (paras.length == 1 && "NBTTagCompound".equals(paras[0].getSimpleName()) && "NBTTagCompound".equals(rt2.getSimpleName())) {
                        Automatic.nmsSaveNBTMethod = method;
                    }
                }
                Automatic.inited = true;
            }
            catch (ClassNotFoundException | NoSuchMethodException ex2) {
                ex2.printStackTrace();
            }
        }
    }
    
    static class Manual extends ItemSerialize
    {
        @Override
        public String getName() {
            return "Manual";
        }
        
        @Override
        public String parse(final ItemStack item) {
            return this.serialize(item);
        }
        
        private String getDisplay(final ItemMeta im) {
            final StringBuilder display = new StringBuilder();
            display.append("{");
            if (im.hasDisplayName()) {
                display.append(String.format("Name:\"%s\",", im.getDisplayName()));
            }
            if (im.hasLore()) {
                display.append("Lore:[");
                int i = 0;
                for (final String line : im.getLore()) {
                    display.append(String.format("%s:\"%s\",", i, new JsonBuilder(line).toString()));
                    ++i;
                }
                display.deleteCharAt(display.length() - 1);
                display.append("],");
            }
            display.deleteCharAt(display.length() - 1);
            display.append("}");
            return display.toString();
        }
        
        private String getEnch(final Set<Map.Entry<Enchantment, Integer>> set) {
            final StringBuilder enchs = new StringBuilder();
            for (final Map.Entry<Enchantment, Integer> ench : set) {
                enchs.append(String.format("{id:%s,lvl:%s},", ench.getKey().getId(), ench.getValue()));
            }
            enchs.deleteCharAt(enchs.length() - 1);
            return enchs.toString();
        }
        
        private String getTag(final ItemMeta im) {
            final StringBuilder meta = new StringBuilder("{");
            if (im.hasEnchants()) {
                meta.append(String.format("ench:[%s],", this.getEnch(im.getEnchants().entrySet())));
            }
            if (im.hasDisplayName() || im.hasLore()) {
                meta.append(String.format("display:%s,", this.getDisplay(im)));
            }
            meta.deleteCharAt(meta.length() - 1);
            meta.append("}");
            return meta.toString();
        }
        
        private String serialize(final ItemStack item) {
            final StringBuilder json = new StringBuilder("{");
            json.append(String.format("id:\"%s\",Damage:\"%s\"", item.getTypeId(), item.getDurability()));
            if (item.getAmount() > 1) {
                json.append(String.format(",Count:%s", item.getAmount()));
            }
            if (item.hasItemMeta()) {
                json.append(String.format(",tag:%s", this.getTag(item.getItemMeta())));
            }
            json.append("}");
            return json.toString();
        }
    }
}
